<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
<script>
    // 面向对象的三大特征: 封装 继承  多态
    // 封装 => 自定义构造函数(ES6 class)

    // 继承  =>  让一个类(构造函数) 继承 另一个类 的属性和方法,还可以 定义 追加 自己的属性和方法
    // 继承的类 => 子类
    // 被继承的类  => 父类

    // 继承的本质: 构造函数中的属性和方法的复用 (实例相关的属性和方法 原型对象相关的属性和方法) 


    // 原型继续 => 子类创建的实例化对象 也可以访问父类原型对象上的方法

    // 一般情况下: 父类和子类是两个不同的构造函数 => 原型链上并无交集
    // p的原型链: p -> Person.prototype  -> Object.prototype -> null
    // yp的原型链: yp ->  YellowPerson.prototype   -> Object.prototype -> null
    // 正常情况下 子类的实例化对象 不能访问 父类的原型对象


    // 

    function Person(name,age){
        this.name = name;
        this.age = age;
    } 

    // 原型对象上的相关属性和方法
    Person.prototype.species = "human";
    Person.prototype.skill = function(){
        console.log("thinging studying");
    }
    Person.prototype.say = function(){
        console.log(this.name,this.age);
    }
    
    // p的原型链: p -> Person.prototype  -> Object.prototype -> null
    var p = new Person("张三",18);
    console.log(p);


    function YellowPerson(name,age,hobby){
        // debugger;
        // this -> 构造函数YellowPerson在执行过程中创建的实例化对象
        // Person.call(this,name,age);  // 调用父类构造函数,强制将父类构造函数中的this指向 子类在执行过程中创建的实例化对象 
        this.hobby = hobby;
    }

    // 方法1 :最简单的原型继承(最low的)
    // 1. 构造函数的原型对象 => 是一个对象,也是可以覆盖的
    // 2. 父类的原型对象  覆盖子类的原型对象  => 浅复制, 可以理解为抛弃了子类原本的原型对象  父类和子类共有一个原型对象(内层空间)
    // 虽然方法弊端很大 => 但是给我们的原型继承提供了思路 => 想让子类的实例化对象 访问 父类的原型对象 => 就要想方设法将父类的原型对象放到子类的实例化对象的原型链上

    // 方法2: 
    // 用父类的实例化对象 覆盖 子类的原型对象  => 间接拓宽了原型链

    // 缺点:
    // 1.  用父类的实例化对象 覆盖 子类的原型对象 => 父类的实例化对象相关的属性也会附加上去 => 多余属性
    // 2.  用父类的实例化对象 覆盖 子类的原型对象 => constructor 没有了 => 写一个假的

    // 改之前
    // p的原型链: p -> Person.prototype  -> Object.prototype -> null
    // yp的原型链: yp ->  YellowPerson.prototype   -> Object.prototype -> null

    // 改之后
    // yp的原型链: yp ->  YellowPerson.prototype(p)  -> Person.prototype  -> Object.prototype -> null

    // 1. new Person("张三",18) => {name,age,[[prototype]]:Person.prototype}
    // 2. YellowPerson.prototype = new Person("张三",18)

    // YellowPerson.prototype = {
    //     name:"张三", //  多余
    //     age:18,  //  多余
    //     [[prototype]]:Person.prototype
    // }

    var proto = new Person("张三",18); // 声明中间变量 存储数据

    // 先删除多余属性    { [[prototype]]:Person.prototype }
    delete proto.name;
    delete proto.age;
    console.log(proto);
   
    YellowPerson.prototype = proto;  //浅复制

    YellowPerson.prototype.constructor = YellowPerson;

    YellowPerson.prototype.speak = function(){
        console.log("chinese");
    }

    // yp的原型链: yp ->  YellowPerson.prototype   -> Object.prototype -> null
    var yp = new YellowPerson("张三",18,"sing");
    console.log(yp);
    // console.log(yp.species);
    // console.log(yp.skill);
    // console.log(yp.say);


    // 问题
    // console.log(p.speak);





</script>
</html>